package http

import (
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
)

// RequestEncode http编码器, 把request对象编码成字节流, 并写入io缓冲区, 根据 RFC2616 规范编码
type RequestEncode struct{}

func (r *RequestEncode) Encoder(request *Request) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = errors.New(fmt.Sprintln("Error encoding request, ", e))
		}
	}()
	if request == nil {
		return errors.New("request cannot be nil")
	}
	if request.BufWriter == nil {
		return errors.New("buffer writer cannot be nil")
	}

	r.line(request)
	r.header(request)
	r.body(request)
	return request.BufWriter.Flush()
}

// 编码请求行
func (r *RequestEncode) line(request *Request) {
	if err := request.BufWriter.WriteString(request.Method + " "); err != nil {
		panic(err)
	}
	if err := request.BufWriter.WriteString(request.RequestURI + " "); err != nil {
		panic(err)
	}
	if err := request.BufWriter.WriteString(request.Proto); err != nil {
		panic(err)
	}
	if err := request.BufWriter.WriteBytes(crlf); err != nil {
		panic(err)
	}
}

// 编码请求头
func (r *RequestEncode) header(request *Request) {
	writeBuffer := request.BufWriter.WriteBuffer()
	if request.Header != nil || len(request.Header) > 0 {
		for name, values := range request.Header {
			if values == nil || len(values) == 0 {
				continue
			}
			if name == "Cookie" {
				r.cookie(request)
				continue
			}
			for _, value := range values {
				if err := writeHeader(writeBuffer, name, value); err != nil {
					panic(err)
				}
			}
		}
	}

	if request.Host != "" && request.Header.Get("Host") == "" {
		if err := writeHeader(writeBuffer, "Host", request.Host); err != nil {
			panic(err)
		}
	}

	if request.body != nil && request.body.size > 0 {
		if err := writeHeader(writeBuffer, "Content-Length", strconv.FormatInt(request.body.size, 10)); err != nil {
			panic(err)
		}
	}
	if err := request.BufWriter.WriteBytes(crlf); err != nil {
		panic(err)
	}
}

// 编码cookie
func (r *RequestEncode) cookie(request *Request) {
	cookies := request.Cookies()
	if cookies == nil || len(cookies) == 0 {
		return
	}
	var cookieValues []string
	for i := 0; i < len(cookies); i++ {
		cookieValues = append(cookieValues, cookies[i].Name+"="+cookies[i].Value)
	}
	if err := writeHeader(request.BufWriter.WriteBuffer(), "Cookie", strings.Join(cookieValues, "; ")); err != nil {
		panic(err)
	}
}

// 编码请求体
func (r *RequestEncode) body(request *Request) {
	if request.body == nil {
		return
	}
	if request.body.size != request.ContentLength {
		panic("Body length error")
	}

	writeBuffer := request.BufWriter.WriteBuffer()
	readBuffer := request.body.buff.ReadBuffer()
	written, err := io.CopyN(writeBuffer, readBuffer, request.ContentLength)
	if err != nil {
		panic(err)
	}
	if written != request.ContentLength {
		panic("Body length error")
	}
}

func NewRequestEncode() *RequestEncode {
	return &RequestEncode{}
}
